package com.pjhouse.core.common.domain;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.apache.commons.lang.StringUtils.isNotEmpty;

import java.util.NoSuchElementException;

/**
 * 这个类用于封装服务接口的返回值
 *
 * 如果业务上成功，isSuccess是true
 * 如果是系统层面错误，hsf服务会抛出异常，不需要用这个对象的isSuccess表示
 * 业务层面上的失败，一律用错误码表示(errorCode)，不使用异常，
 * 每个errorCode必须对应一条errorMessage，写入配置文件ErrorMessage_zh_CN.properties中（注意编码）
 *
 * 上述约定只限于服务接口设计
 *
 * @author 辰战
 * @version [1.0, 12-3-26]
 * @since 12-3-22
 */
public final class Result<T> extends BaseDTO {

    private static final long serialVersionUID = 1L;
    public static final String ERROR_MESSAGE_RESOURCE_FILE = "ErrorMessage";

    /*　当前业务接口成功或者失败 */
    private final boolean success;

    /* 业务接口失败时返回的错误码　*/
    private String errorCode;

    /* 异常信息 */
    private String exceptionInfo;

    /* 业务接口成功时的返回值　*/
    private T value;

    /* 错误信息 */
    private String errorMessage;

    /**
     * 业务接口成功时，使用这个构造函数构造对象
     *
     * @param value　接口的返回值
     */
    private Result(final T value, final boolean success) {
        this.value = value;
        this.success = success;
    }

    /**
     * 接口失败的时候，使用这个构造函数构造对象
     *
     * @param errorCode　错误码
     */
    private Result(final String errorCode, final String exceptionInfo, final String errorMessage) {
        this.errorCode = errorCode;
        this.exceptionInfo = exceptionInfo;
        this.errorMessage = errorMessage;

        this.success = false;
    }

    /**
     * 业务接口操作是否成功
     *
     * @return 成功时返回true
     */
    public boolean isSuccess() {
        return success;
    }

    /**
     * 业务接口操作是否失败
     *
     * @return 失败时返回true
     */
    public boolean isFailure() {
        return !success;
    }

    /**
     * 当接口操作失败的时候，没有返回值，此方法不能调用
     *
     * @return 接口返回值
     */
    public T getValue() {
        if (isFailure())    throw new NoSuchElementException();

        return this.value;
    }

    /**
     * 当接口操作失败的时候，获取错误码
     *
     * @return String　返回错误码
     */
    public String getErrorCode() {
        if (isSuccess())    throw new NoSuchElementException();

        return errorCode;
    }

    /**
     * 当接口操作失败的时候，获取错误信息
     *
     * @return String 返回具体的错误信息
     */
    public String getErrorMessage() {
        if (isSuccess()) throw new NoSuchElementException();


        if (isNotEmpty(errorMessage)) {
            return errorMessage;
        }

        final String errorCode = getErrorCode();
        if (isEmpty(errorCode)) {
            return exceptionInfo;
        }

        checkState(isNotEmpty(errorMessage), "result is failure but no error message");

        return errorMessage;

    }

    /**
     * 静态方法构建成功的Result对象，实现类模版自动类型匹配
     * 业务操作成功则使用该方法构建
     *
     * @param value 接口的返回值
     * @param <T> 返回值类型
     * @return 封装了返回值的result对象
     */
    public static <T> Result<T> of(T value) {
        return new Result<T>(checkNotNull(value), true);
    }

    /**
     * 静态方法构建失败的Result对象，实现类模版自动类型匹配
     * 业务操作失败则使用该方法构建
     *
     * @param errorCode　错误码
     * @param <T>  返回值类型
     * @return 封装了错误码的result对象
     */
    public static <T> Result<T> errorCode(String errorCode) {
        checkArgument(errorCode != null && errorCode.length() > 0);
        return new Result<T>(errorCode, null, null);
    }

    /**
     * 静态方法构建失败的Result对象，实现类模版自动类型匹配
     * 业务操作失败则使用该方法构建
     *
     * @param exceptionInfo　错误码
     * @param <T>  返回值类型
     * @return 封装了错误码的result对象
     */
    public static <T> Result<T> exceptionInfo(String exceptionInfo) {
        checkArgument(exceptionInfo != null && exceptionInfo.length() > 0);

        return new Result<T>(null, exceptionInfo, null);
    }

    /**
     * 静态方法构建失败的Result对象，实现类模版自动类型匹配
     * 业务操作失败则使用该方法构建
     *
     * @param errorMessage　错误码
     * @param <T>  返回值类型
     * @return 封装了错误码的result对象
     */
    public static <T> Result<T> errorMessage(String errorMessage) {
        checkArgument(errorMessage != null && errorMessage.length() > 0);

        return new Result<T>(null, null, errorMessage);
    }

    /**
     * 静态方法构建成功的Result对象
     *
     * @param <T>
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
	public static <T> Result<T> success() {
        return new Result(true, true);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> Result<T> ofNull() {
        return new Result(null, true);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> Result<T> ofVoid() {
        return new Result(null, true);
    }
    
}